﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using System.Drawing;
using TTServer.Messages;
using TTServer.Utilities;
using libUtilities;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace TTServer
{
    public class ScreenshotBroadcastWithFeedback
    {
        private static ScreenshotBroadcastWithFeedback _instance;

        public static ScreenshotBroadcastWithFeedback GetInstance()
        {
            try
            {
                if (_instance == null)
                {
                    _instance = new ScreenshotBroadcastWithFeedback();
                }

                return _instance;
            }
            catch
            {
                return null;
            }
        }

        public static void TryToStart()
        {
            ScreenshotBroadcastWithFeedback bss = ScreenshotBroadcastWithFeedback.GetInstance();

            if (bss != null)
            {
                bss.Start();
            }
        }

        public static void TryToStop()
        {
            ScreenshotBroadcastWithFeedback bss = ScreenshotBroadcastWithFeedback.GetInstance();

            if (bss != null)
            {
                bss.Stop();
            }
        }

        private static int HEADER_SIZE = 8;
        private static int MAX_DATA_SIZE = 65499;
        private static int MAX_PACKETS = 50;
        private static int SESSION_START = 128;
        private static int SESSION_END = 64;
        private static int MAX_SESSION_NUMBER = 7200;

        private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
        private ManualResetEvent _noPauseEvent = new ManualResetEvent(true);

        private Thread _thread = null;

        private bool _bStoped = false;

        private bool _bFirst = true;

        private Socket _UDPServerSocket;
        IPEndPoint ipep_broadcast_11111;

        public ScreenshotBroadcastWithFeedback()
        {
            IPEndPoint bindingIpEp = new IPEndPoint(IPAddress.Any, 12345);

            _UDPServerSocket = new Socket(AddressFamily.InterNetwork,
                    SocketType.Dgram, ProtocolType.Udp);

            _UDPServerSocket.Bind(bindingIpEp);

            _UDPServerSocket.SetSocketOption(SocketOptionLevel.Socket,
                       SocketOptionName.Broadcast, 1);

            int sockopt = (int)_UDPServerSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
            Console.WriteLine("Default timeout: {0}", sockopt);

            _UDPServerSocket.SetSocketOption(SocketOptionLevel.Socket,
             SocketOptionName.ReceiveTimeout, 50);

            sockopt = (int)_UDPServerSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout);
            Console.WriteLine("New timeout: {0}", sockopt);

            ipep_broadcast_11111 = new IPEndPoint(IPAddress.Broadcast, 11111);

            _shutdownEvent = new ManualResetEvent(false);
            _noPauseEvent = new ManualResetEvent(true);

            ThreadStart threadStart = new ThreadStart(Run);
            _thread = new Thread(threadStart);
            _thread.IsBackground = true;

            
        }

        public void Start()
        {
            

            if (_bFirst)
            {
                _thread.Start();
                _bFirst = false;
                return;
            }
            else if (_bStoped)
            {
                _shutdownEvent = new ManualResetEvent(false);
                _noPauseEvent = new ManualResetEvent(true);

                ThreadStart threadStart = new ThreadStart(Run);
                _thread = new Thread(threadStart);
                _thread.IsBackground = true;
                _thread.Start();

                _bStoped = false;
            }
            else
            {
                Stop();

                _shutdownEvent = new ManualResetEvent(false);
                _noPauseEvent = new ManualResetEvent(true);

                ThreadStart threadStart = new ThreadStart(Run);
                _thread = new Thread(threadStart);
                _thread.IsBackground = true;
                _thread.Start();

                _bStoped = false;
            }
        }

        public void Pause()
        {
            _noPauseEvent.Reset();
        }

        public void Resume()
        {
            _noPauseEvent.Set();
        }

        public void Stop()
        {
            if (_bStoped == false)
            {
                // Signal the shutdown event
                _shutdownEvent.Set();

                // Make sure to resume any paused threads
                _noPauseEvent.Set();

                // Wait for the thread to exit
                _thread.Join();

                _bStoped = true;
            }
        }

        private Bitmap CaptureScreen()
        {
            Size size = new Size(Screen.PrimaryScreen.Bounds.Width,
                Screen.PrimaryScreen.Bounds.Height);

            Bitmap bitmap = new Bitmap(size.Width, size.Height);

            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                graphics.CopyFromScreen(new Point(0, 0), new Point(0, 0), size);
            }

            //return ImageUtils.MakeGrayscale(bitmap);

            return bitmap;
        }

        public byte[] getImageByteArrayFromSlideShowView()
        {
            var img = this.CaptureScreen();

            if (img == null)
                return null;

            var smallImg = ImageUtils.resizeImage(img, new Size(img.Width / 2, img.Height / 2));

            //var smallImg = ImageUtils.resizeImage(img, new Size(800, 480));


            using (var ms = new System.IO.MemoryStream())
            {
                smallImg.Save(ms, System.Drawing.Imaging.ImageFormat.Png);

                try
                {
                    smallImg.Dispose();
                    img.Dispose();
                }
                catch
                { 
                
                }

                return ms.ToArray();
            }
        }

        public void Run()
        {


            byte[] imageByteArray = null;

            int sessionNumber = 0;

            try
            {
                while (true)
                {
                    _noPauseEvent.WaitOne(Timeout.Infinite);

                    if (_shutdownEvent.WaitOne(0))
                        break;

                    imageByteArray = getImageByteArrayFromSlideShowView();

                    if (imageByteArray != null)
                    {
                        // Calculate the number of packets to be sent in the current session.
                        int a = imageByteArray.Length / MAX_DATA_SIZE;
                        int b = (imageByteArray.Length % MAX_DATA_SIZE) > 0 ? 1 : 0;
                        int i_packets = a + b;

                        if (i_packets > MAX_PACKETS)
                        {
                            throw (new Exception("packets > MAX_PACKETS"));
                        }

                        for (int i = 0; i < i_packets; i++)
                        {
                            int flags = 0;
                            flags = (i == 0) ? (flags | SESSION_START) : flags;
                            flags = (i == (i_packets - 1)) ? (flags | SESSION_END) : flags;

                            int size = ((flags & SESSION_END) != SESSION_END)
                                ? MAX_DATA_SIZE
                                : imageByteArray.Length - i * MAX_DATA_SIZE;

                            byte[] data = new byte[HEADER_SIZE + size];
                            data[0] = (byte)flags;
                            data[1] = (byte)sessionNumber;
                            data[2] = (byte)i_packets;
                            data[3] = (byte)(MAX_DATA_SIZE >> 8);
                            data[4] = (byte)MAX_DATA_SIZE;
                            data[5] = (byte)i;
                            data[6] = (byte)(size >> 8);
                            data[7] = (byte)size;

                            Array.Copy(imageByteArray, i * MAX_DATA_SIZE, data, HEADER_SIZE, size);

                            ////////////////////////////////////////////////////
                            //server.SendTo(data, iep);
                            //Thread.Sleep(300);
                            ////////////////////////////////////////////////////

                            int recv = SndRcvData(_UDPServerSocket, data, ipep_broadcast_11111);
                            if (recv == -1)
                            {
                                break;
                            }
                            else if (recv == 0)
                            {
                                //string strStop = "STOP";
                                //byte[] strStopData = Encoding.ASCII.GetBytes(strStop);

                                //_UDPServerSocket.SendTo(strStopData, ipep_broadcast_11111);
                                //Thread.Sleep(300);

                                //_UDPServerSocket.SendTo(strStopData, ipep_broadcast_11111);
                                //Thread.Sleep(300);

                                //Pause();

                                //break;
                            }
                            else
                            {
                                if (recv > 0)
                                {
                                    String stringData = Encoding.ASCII.GetString(receivingData, 0, recv);
                                    if ("OK ADMIN".Equals(stringData))
                                    {
                                        Thread.Sleep(200);
                                    }

                                }
                            }
                            //////////////////////////////////////////////////

                            //if (i != 0)
                            //{
                            //    sock.SendTo(data, iep);

                            //    Thread.Sleep(300);
                            //}

                            if (_shutdownEvent.WaitOne(0))
                                break;

                        } // for (int i = 0; i < i_packets; i++)

                        sessionNumber = sessionNumber < MAX_SESSION_NUMBER ? ++sessionNumber : 0;

                    } // if (imageByteArray != null)

                    //Thread.Sleep(100);

                } // while (true)
            }
            catch (Exception ex)
            {
                String str = ex.Message;
            }
        }


        private byte[] receivingData = new byte[65507];
        private static IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
        private static EndPoint Remote = (EndPoint)sender;

        private int SndRcvData(Socket s, byte[] message, EndPoint rmtdevice)
        {
            int recv;
            int retry = 0;
            while (true)
            {
                Console.WriteLine("Attempt #{0}", retry);
                try
                {
                    s.SendTo(message, message.Length, SocketFlags.None, rmtdevice);

                    recv = s.ReceiveFrom(receivingData, ref Remote);
                }
                catch (SocketException)
                {
                    recv = 0;
                }

                if (recv > 0)
                {
                    return recv;
                }
                else
                {
                    Thread.Sleep(200);

                    retry++;

                    if (retry > 50)
                    {
                        return 0;
                    }
                }

                if (_shutdownEvent.WaitOne(0))
                    return -1;
            }
        }



    }
}
